/*
 * Copyright 2002-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.aop.config;

import java.util.ArrayList;
import java.util.List;

import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import org.springframework.aop.aspectj.AspectJAfterAdvice;
import org.springframework.aop.aspectj.AspectJAfterReturningAdvice;
import org.springframework.aop.aspectj.AspectJAfterThrowingAdvice;
import org.springframework.aop.aspectj.AspectJAroundAdvice;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.AspectJMethodBeforeAdvice;
import org.springframework.aop.aspectj.AspectJPointcutAdvisor;
import org.springframework.aop.aspectj.DeclareParentsAdvisor;
import org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanReference;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.RuntimeBeanNameReference;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.parsing.ParseState;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;

/**
 * {@link BeanDefinitionParser} for the {@code <aop:config>} tag.
 *
 * @author Rob Harrop
 * @author Juergen Hoeller
 * @author Adrian Colyer
 * @author Mark Fisher
 * @author Ramnivas Laddad
 * @since 2.0
 */
class ConfigBeanDefinitionParser implements BeanDefinitionParser {

	private static final String ASPECT = "aspect";
	private static final String EXPRESSION = "expression";
	private static final String ID = "id";
	private static final String POINTCUT = "pointcut";
	private static final String ADVICE_BEAN_NAME = "adviceBeanName";
	private static final String ADVISOR = "advisor";
	private static final String ADVICE_REF = "advice-ref";
	private static final String POINTCUT_REF = "pointcut-ref";
	private static final String REF = "ref";
	private static final String BEFORE = "before";
	private static final String DECLARE_PARENTS = "declare-parents";
	private static final String TYPE_PATTERN = "types-matching";
	private static final String DEFAULT_IMPL = "default-impl";
	private static final String DELEGATE_REF = "delegate-ref";
	private static final String IMPLEMENT_INTERFACE = "implement-interface";
	private static final String AFTER = "after";
	private static final String AFTER_RETURNING_ELEMENT = "after-returning";
	private static final String AFTER_THROWING_ELEMENT = "after-throwing";
	private static final String AROUND = "around";
	private static final String RETURNING = "returning";
	private static final String RETURNING_PROPERTY = "returningName";
	private static final String THROWING = "throwing";
	private static final String THROWING_PROPERTY = "throwingName";
	private static final String ARG_NAMES = "arg-names";
	private static final String ARG_NAMES_PROPERTY = "argumentNames";
	private static final String ASPECT_NAME_PROPERTY = "aspectName";
	private static final String DECLARATION_ORDER_PROPERTY = "declarationOrder";
	private static final String ORDER_PROPERTY = "order";
	private static final int METHOD_INDEX = 0;
	private static final int POINTCUT_INDEX = 1;
	private static final int ASPECT_INSTANCE_FACTORY_INDEX = 2;

	private ParseState parseState = new ParseState();


	/**
	 * 将AOP命名空间中的顶级元素解析为Spring组件定义。
	 * 该方法处理<aop:config>根标签及其子元素，构建AOP基础设施组件（如自动代理创建器、切点、增强器和切面）。
	 *
	 * @param element 需要解析的XML元素（通常是<aop:config>标签）
	 * @param parserContext 解析上下文，包含注册表、委托解析器和源提取器
	 * @return 始终返回null（因为该方法注册的是复合组件，而非单个BeanDefinition）
	 *
	 * @throws IllegalArgumentException 当遇到未知子元素类型时抛出
	 *
	 * 解析流程：
	 * 1. 创建一个复合组件定义，用于封装所有子组件
	 * 2. 配置自动代理创建器（若尚未配置）
	 * 3. 遍历子元素并根据标签类型调用相应解析器：
	 *    - <aop:pointcut>：定义切入点表达式
	 *    - <aop:advisor>：定义包含切入点和增强逻辑的增强器
	 *    - <aop:aspect>：定义包含多个切点和增强的切面
	 * 4. 将复合组件注册到上下文
	 *
	 * 设计要点：
	 * - 使用CompositeComponentDefinition聚合多个相关组件
	 * - 通过ParserContext维护解析栈，确保嵌套组件正确注册
	 * - 自动代理创建器负责在运行时为匹配的Bean生成代理对象
	 *
	 * 使用示例：
	 * <aop:config>
	 *   <aop:pointcut id="servicePointcut" expression="execution(* com.example.service.*.*(..))"/>
	 *   <aop:advisor pointcut-ref="servicePointcut" advice-ref="loggingAdvice"/>
	 * </aop:config>
	 *
	 * 以上配置会被解析为：
	 * 1. 一个切入点组件，匹配所有Service层方法
	 * 2. 一个增强器组件，将日志增强应用到切入点匹配的目标
	 */
	@Override
	@Nullable
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		// 创建复合组件定义，用于封装所有子组件（如切入点、增强器等）
		CompositeComponentDefinition compositeDef =
				new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
		parserContext.pushContainingComponent(compositeDef);

		// 确保自动代理创建器已注册（用于生成AOP代理对象）
		configureAutoProxyCreator(parserContext, element);

		// 处理所有子元素，这个是处理一级标签先的
		/*
		*
	<aop:config>
        <aop:aspect ref="logUtil">  第一级标签
            <aop:pointcut id="myPoint" expression="execution( Integer com.elephant.aop.xml.service.MyCalculator.*  (..))"/>
            <aop:around method="around" pointcut-ref="myPoint"></aop:around>
            <aop:before method="start" pointcut-ref="myPoint"></aop:before>
            <aop:after method="logFinally" pointcut-ref="myPoint"></aop:after>
            <aop:after-returning method="stop" pointcut-ref="myPoint" returning="result"></aop:after-returning>
            <aop:after-throwing method="logException" pointcut-ref="myPoint" throwing="e"></aop:after-throwing>
        </aop:aspect>
    </aop:config>*/

		List<Element> childElts = DomUtils.getChildElements(element);
		for (Element elt: childElts) {
			String localName = parserContext.getDelegate().getLocalName(elt);
			// 根据标签类型分发到不同的解析方法，找到对应的一级标签，进去处理二级标签
			if (POINTCUT.equals(localName)) {
				parsePointcut(elt, parserContext);
			}
			else if (ADVISOR.equals(localName)) {
				parseAdvisor(elt, parserContext);
			}
			else if (ASPECT.equals(localName)) {
				parseAspect(elt, parserContext);
			}
			else {
				throw new IllegalArgumentException("未知的AOP配置元素: " + localName);
			}
		}

		// 从解析栈弹出当前复合组件并注册到应用上下文中
		parserContext.popAndRegisterContainingComponent();
		return null;
	}
	/**
	 * 配置支持由<aop:config/>标签创建的BeanDefinition所需的自动代理创建器。
	 * 该方法会根据标签属性决定代理创建策略，并注册相应的自动代理创建器到应用上下文中。
	 *
	 * <p>当<aop:config proxy-target-class="true"/>时，强制使用CGLIB基于类的代理方式；
	 * 当proxy-target-class="false"或未指定该属性时，使用基于接口的JDK动态代理。
	 *
	 * <p>此方法通过调用AopNamespaceUtils工具类完成实际的注册逻辑，
	 * 会确保在应用上下文中存在且仅存在一个符合条件的自动代理创建器。
	 *
	 * @param parserContext 解析器上下文，包含当前解析环境的上下文信息
	 * @param element 当前正在解析的<aop:config/>标签元素
	 *
	 * @see AopNamespaceUtils#registerAspectJAutoProxyCreatorIfNecessary(ParserContext, Element)
	 * @see org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator
	 * @see org.springframework.aop.framework.ProxyFactoryBean
	 */
	private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
		// 注册AspectJ风格的自动代理创建器（如果必要）
		// 该工具方法会处理代理策略配置，并确保自动代理基础设施正确初始化
		AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
	}

	/**
	 * Parses the supplied {@code <advisor>} element and registers the resulting
	 * {@link org.springframework.aop.Advisor} and any resulting {@link org.springframework.aop.Pointcut}
	 * with the supplied {@link BeanDefinitionRegistry}.
	 */
	private void parseAdvisor(Element advisorElement, ParserContext parserContext) {
		AbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext);
		String id = advisorElement.getAttribute(ID);

		try {
			this.parseState.push(new AdvisorEntry(id));
			String advisorBeanName = id;
			if (StringUtils.hasText(advisorBeanName)) {
				parserContext.getRegistry().registerBeanDefinition(advisorBeanName, advisorDef);
			}
			else {
				advisorBeanName = parserContext.getReaderContext().registerWithGeneratedName(advisorDef);
			}

			Object pointcut = parsePointcutProperty(advisorElement, parserContext);
			if (pointcut instanceof BeanDefinition) {
				advisorDef.getPropertyValues().add(POINTCUT, pointcut);
				parserContext.registerComponent(
						new AdvisorComponentDefinition(advisorBeanName, advisorDef, (BeanDefinition) pointcut));
			}
			else if (pointcut instanceof String) {
				advisorDef.getPropertyValues().add(POINTCUT, new RuntimeBeanReference((String) pointcut));
				parserContext.registerComponent(
						new AdvisorComponentDefinition(advisorBeanName, advisorDef));
			}
		}
		finally {
			this.parseState.pop();
		}
	}

	/**
	 * Create a {@link RootBeanDefinition} for the advisor described in the supplied. Does <strong>not</strong>
	 * parse any associated '{@code pointcut}' or '{@code pointcut-ref}' attributes.
	 */
	private AbstractBeanDefinition createAdvisorBeanDefinition(Element advisorElement, ParserContext parserContext) {
		RootBeanDefinition advisorDefinition = new RootBeanDefinition(DefaultBeanFactoryPointcutAdvisor.class);
		advisorDefinition.setSource(parserContext.extractSource(advisorElement));

		String adviceRef = advisorElement.getAttribute(ADVICE_REF);
		if (!StringUtils.hasText(adviceRef)) {
			parserContext.getReaderContext().error(
					"'advice-ref' attribute contains empty value.", advisorElement, this.parseState.snapshot());
		}
		else {
			advisorDefinition.getPropertyValues().add(
					ADVICE_BEAN_NAME, new RuntimeBeanNameReference(adviceRef));
		}

		if (advisorElement.hasAttribute(ORDER_PROPERTY)) {
			advisorDefinition.getPropertyValues().add(
					ORDER_PROPERTY, advisorElement.getAttribute(ORDER_PROPERTY));
		}

		return advisorDefinition;
	}
	/**
	 * 解析<aop:aspect>标签，将其转换为Spring AOP的切面组件定义。
	 * 该方法处理切面内部的所有元素，包括引入增强(declare-parents)、
	 * 各种通知(advice)和切入点(pointcut)。
	 *
	 * @param aspectElement 需要解析的XML切面元素
	 * @param parserContext 解析上下文，包含组件注册器和源信息提取器
	 *
	 * @throws IllegalArgumentException 当切面配置不合法时抛出（如缺少ref属性但定义了通知）
	 *
	 * 解析流程：
	 * 1. 提取切面ID和引用的Bean名称
	 * 2. 处理所有declare-parents元素（类型引入增强）
	 * 3. 按顺序处理所有通知元素（前置、后置、环绕等）
	 * 4. 创建切面组件定义并注册到上下文
	 * 5. 处理切面内定义的本地切入点
	 *
	 * 配置约束：
	 * - 如果切面包含通知，则必须通过'ref'属性引用一个实际的Bean
	 * - 通知元素必须出现在所有切入点定义之后
	 * - declare-parents增强必须在通知之前定义
	 *
	 * 内部数据结构：
	 * - beanDefinitions: 存储解析过程中创建的所有BeanDefinition
	 * - beanReferences: 存储切面引用的所有Bean（通常是切面实例本身）
	 *
	 * 使用示例：
	 * <aop:aspect id="myAspect" ref="aspectBean">
	 *   <aop:declare-parents types-matching="com.x.*" implement-interface="com.x.MyInterface"/>
	 *   <aop:before method="beforeAdvice" pointcut-ref="myPointcut"/>
	 *   <aop:pointcut id="myPointcut" expression="execution(* com.x.service.*(..))"/>
	 * </aop:aspect>
	 */
	private void parseAspect(Element aspectElement, ParserContext parserContext) {
		// 提取切面的标识和引用的Bean（切面实例）
		String aspectId = aspectElement.getAttribute(ID);
		String aspectName = aspectElement.getAttribute(REF);

		try {
			// 记录解析状态，用于错误跟踪和嵌套组件管理
			this.parseState.push(new AspectEntry(aspectId, aspectName));
			List<BeanDefinition> beanDefinitions = new ArrayList<>();
			List<BeanReference> beanReferences = new ArrayList<>();

			// 1. 处理类型引入增强（declare-parents）
			// 允许切面为匹配的类型实现额外接口
			List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
			for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
				Element declareParentsElement = declareParents.get(i);
				beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
			}

			// 2. 按顺序处理所有通知元素（前置、后置、环绕等）
			// 注意：通知必须在所有切入点定义之后出现
			NodeList nodeList = aspectElement.getChildNodes();//找到所有二级标签进行解析咯
			boolean adviceFoundAlready = false;
			for (int i = 0; i < nodeList.getLength(); i++) {
				Node node = nodeList.item(i);
				if (isAdviceNode(node, parserContext)) {
					// 首次发现通知时，验证切面引用是否存在
					if (!adviceFoundAlready) {
						adviceFoundAlready = true;
						if (!StringUtils.hasText(aspectName)) {
							parserContext.getReaderContext().error(
									"<aspect>标签在定义通知时必须通过'ref'属性引用切面Bean",
									aspectElement, this.parseState.snapshot());
							return;
						}
						// 记录切面实例的引用
						beanReferences.add(new RuntimeBeanReference(aspectName));
					}
					// 解析具体的通知并创建增强器定义
					AbstractBeanDefinition advisorDefinition = parseAdvice(
							aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
					beanDefinitions.add(advisorDefinition);
				}
			}

			// 3. 创建切面组件定义并将其压入解析栈
			AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(
					aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
			parserContext.pushContainingComponent(aspectComponentDefinition);

			// 4. 处理切面内定义的本地切入点
			List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
			for (Element pointcutElement : pointcuts) {
				parsePointcut(pointcutElement, parserContext);
			}

			// 5. 弹出并注册切面组件
			parserContext.popAndRegisterContainingComponent();
		}
		finally {
			// 清理解析状态，确保嵌套结构正确
			this.parseState.pop();
		}
	}

	private AspectComponentDefinition createAspectComponentDefinition(
			Element aspectElement, String aspectId, List<BeanDefinition> beanDefs,
			List<BeanReference> beanRefs, ParserContext parserContext) {

		BeanDefinition[] beanDefArray = beanDefs.toArray(new BeanDefinition[0]);
		BeanReference[] beanRefArray = beanRefs.toArray(new BeanReference[0]);
		Object source = parserContext.extractSource(aspectElement);
		return new AspectComponentDefinition(aspectId, beanDefArray, beanRefArray, source);
	}

	/**
	 * 判断给定的节点是否描述了一个AOP通知类型。
	 * 支持的通知类型包括:
	 * - "before": 前置通知（方法执行前）
	 * - "after": 后置通知（方法执行后，无论是否异常）
	 * - "after-returning": 返回通知（方法正常返回后）
	 * - "after-throwing": 异常通知（方法抛出异常后）
	 * - "around": 环绕通知（包裹方法执行的全过程）
	 *
	 * @param aNode 当前正在解析的DOM节点
	 * @param parserContext Spring解析上下文，提供解析工具和环境
	 * @return 如果节点是有效的通知类型节点返回true，否则返回false
	 */
	private boolean isAdviceNode(Node aNode, ParserContext parserContext) {
		// 首先检查节点是否为Element类型，只有Element节点才可能是有效的通知配置
		if (!(aNode instanceof Element)) {
			return false;
		}
		else {
			// 获取节点的本地名称（不包含命名空间前缀）
			String name = parserContext.getDelegate().getLocalName(aNode);

			// 检查节点名称是否匹配任何已知的通知类型
			return (BEFORE.equals(name) || AFTER.equals(name) || AFTER_RETURNING_ELEMENT.equals(name) ||
					AFTER_THROWING_ELEMENT.equals(name) || AROUND.equals(name));
		}
	}

	/**
	 * Parse a '{@code declare-parents}' element and register the appropriate
	 * DeclareParentsAdvisor with the BeanDefinitionRegistry encapsulated in the
	 * supplied ParserContext.
	 */
	private AbstractBeanDefinition parseDeclareParents(Element declareParentsElement, ParserContext parserContext) {
		BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(DeclareParentsAdvisor.class);
		builder.addConstructorArgValue(declareParentsElement.getAttribute(IMPLEMENT_INTERFACE));
		builder.addConstructorArgValue(declareParentsElement.getAttribute(TYPE_PATTERN));

		String defaultImpl = declareParentsElement.getAttribute(DEFAULT_IMPL);
		String delegateRef = declareParentsElement.getAttribute(DELEGATE_REF);

		if (StringUtils.hasText(defaultImpl) && !StringUtils.hasText(delegateRef)) {
			builder.addConstructorArgValue(defaultImpl);
		}
		else if (StringUtils.hasText(delegateRef) && !StringUtils.hasText(defaultImpl)) {
			builder.addConstructorArgReference(delegateRef);
		}
		else {
			parserContext.getReaderContext().error(
					"Exactly one of the " + DEFAULT_IMPL + " or " + DELEGATE_REF + " attributes must be specified",
					declareParentsElement, this.parseState.snapshot());
		}

		AbstractBeanDefinition definition = builder.getBeanDefinition();
		definition.setSource(parserContext.extractSource(declareParentsElement));
		parserContext.getReaderContext().registerWithGeneratedName(definition);
		return definition;
	}

	/**
	 * 解析通知元素并创建对应的 BeanDefinition，支持五种通知类型：
	 * before、after、after-returning、after-throwing 和 around
	 *
	 * @param aspectName       切面 Bean 的名称
	 * @param order            切面执行顺序
	 * @param aspectElement    切面 XML 元素
	 * @param adviceElement    通知 XML 元素
	 * @param parserContext    解析上下文
	 * @param beanDefinitions  用于存储临时 BeanDefinition 的列表
	 * @param beanReferences   用于存储临时 BeanReference 的列表
	 * @return 生成的通知 BeanDefinition
	 */
	private AbstractBeanDefinition parseAdvice(
			String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
			List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {

		try {
			// 记录解析状态，用于调试和错误处理
			this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));

			// 1. 创建方法定位工厂 BeanDefinition
			// 该工厂用于定位切面类中定义的通知方法
			RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
			methodDefinition.getPropertyValues().add("targetBeanName", aspectName); // 指定目标切面 Bean
			methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method")); // 指定方法名
			methodDefinition.setSynthetic(true); // 标记为合成 Bean，不参与常规 Bean 生命周期

			// 2. 创建切面实例工厂 BeanDefinition
			// 该工厂用于创建切面实例
			RootBeanDefinition aspectFactoryDef =
					new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
				aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName); // 指定切面 Bean
				aspectFactoryDef.setSynthetic(true); // 标记为合成 Bean

			// 3. 创建具体通知类型的 BeanDefinition
			// 根据通知类型(如 before/after/around)创建对应的通知 BeanDefinition
			AbstractBeanDefinition adviceDef = createAdviceDefinition(
					adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
					beanDefinitions, beanReferences);

			// 4. 创建切面切入点通知 BeanDefinition
			// 该通知将通知和切入点关联起来
			RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
			advisorDefinition.setSource(parserContext.extractSource(adviceElement)); // 设置来源，用于调试
			advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef); // 注入通知
			// 如果切面定义了顺序属性，则添加到通知
			if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
				advisorDefinition.getPropertyValues().add(
						ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
			}

			// 5. 注册最终的通知 BeanDefinition
			// 使用生成的名称注册到 BeanDefinitionRegistry
			parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);

			return advisorDefinition;
		}
		finally {
			// 清理解析状态
			this.parseState.pop();
		}
	}
	/**
	 * 创建用于POJO通知(Advice)的RootBeanDefinition。同时触发切入点(Pointcut)解析，
	 * 以便将切入点与通知bean关联。此切入点也会通过提供的MutablePropertyValues
	 * 配置为封装的Advisor定义的切入点。
	 *
	 * @param adviceElement 当前解析的<aop:xxx>通知元素
	 * @param parserContext Spring解析上下文
	 * @param aspectName 声明此通知的切面名称
	 * @param order 通知在切面内的声明顺序
	 * @param methodDef 定义通知逻辑的方法的BeanDefinition
	 * @param aspectFactoryDef 切面实例工厂的BeanDefinition
	 * @param beanDefinitions 用于收集新创建的BeanDefinition的列表
	 * @param beanReferences 用于收集新创建的BeanReference的列表
	 * @return 配置好的通知BeanDefinition
	 */
	private AbstractBeanDefinition createAdviceDefinition(
			Element adviceElement, ParserContext parserContext, String aspectName, int order,
			RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
			List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {

		// 创建通知BeanDefinition，指定通知类(如MethodBeforeAdviceInterceptor)
		RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
		adviceDefinition.setSource(parserContext.extractSource(adviceElement));

		// 设置切面名称和声明顺序属性，这些属性会在通知实例化时注入
		adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
		adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);

		// 处理@AfterReturning注解对应的returning属性
		if (adviceElement.hasAttribute(RETURNING)) {
			adviceDefinition.getPropertyValues().add(
					RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
		}

		// 处理@AfterThrowing注解对应的throwing属性
		if (adviceElement.hasAttribute(THROWING)) {
			adviceDefinition.getPropertyValues().add(
					THROWING_PROPERTY, adviceElement.getAttribute(THROWING));
		}

		// 处理参数名称绑定属性(如args(param1,param2))
		if (adviceElement.hasAttribute(ARG_NAMES)) {
			adviceDefinition.getPropertyValues().add(
					ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES));
		}

		// 配置通知实例化的构造参数
		ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();

		// 第一个参数：通知方法的Method对象定义
		cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);

		// 解析切入点表达式并配置为第二个构造参数  , 解析point-cut属性
		Object pointcut = parsePointcutProperty(adviceElement, parserContext);
		if (pointcut instanceof BeanDefinition) {
			// 内联切入点表达式：创建新的Pointcut BeanDefinition
			cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut);
			beanDefinitions.add((BeanDefinition) pointcut);
		}
		else if (pointcut instanceof String) {
			// 引用外部切入点：创建对已有Pointcut的引用
			RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);
			cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef);
			beanReferences.add(pointcutRef);
		}

		// 第三个参数：切面实例工厂，用于获取切面实例
		cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);

		return adviceDefinition;
	}
	/**
	 * 根据提供的XML元素，获取对应的AOP通知(Advice)实现类。
	 * 该方法将Spring AOP的XML配置元素映射到对应的AspectJ通知拦截器类。
	 *
	 * 支持的映射关系包括：
	 * - <aop:before>    → AspectJMethodBeforeAdvice
	 * - <aop:after>     → AspectJAfterAdvice
	 * - <aop:after-returning> → AspectJAfterReturningAdvice
	 * - <aop:after-throwing>  → AspectJAfterThrowingAdvice
	 * - <aop:around>    → AspectJAroundAdvice
	 *
	 * @param adviceElement 表示AOP通知的XML元素
	 * @param parserContext Spring配置解析上下文
	 * @return 与XML元素对应的通知拦截器实现类
	 * @throws IllegalArgumentException 当传入未知的通知元素类型时抛出
	 */
	private Class<?> getAdviceClass(Element adviceElement, ParserContext parserContext) {
		// 获取XML元素的本地名称(如"before"、"around"等)
		String elementName = parserContext.getDelegate().getLocalName(adviceElement);

		// 根据元素名称映射到对应的通知拦截器类
		if (BEFORE.equals(elementName)) {
			// 前置通知：在目标方法执行前执行
			return AspectJMethodBeforeAdvice.class;
		}
		else if (AFTER.equals(elementName)) {
			// 后置通知：无论目标方法是否正常返回或抛出异常都会执行
			return AspectJAfterAdvice.class;
		}
		else if (AFTER_RETURNING_ELEMENT.equals(elementName)) {
			// 返回通知：在目标方法正常返回后执行
			return AspectJAfterReturningAdvice.class;
		}
		else if (AFTER_THROWING_ELEMENT.equals(elementName)) {
			// 异常通知：在目标方法抛出异常后执行
			return AspectJAfterThrowingAdvice.class;
		}
		else if (AROUND.equals(elementName)) {
			// 环绕通知：完全控制目标方法的执行时机和方式
			return AspectJAroundAdvice.class;
		}
		else {
			// 未知元素类型处理
			throw new IllegalArgumentException("Unknown advice kind [" + elementName + "].");
		}
	}

	/**
	 * Parses the supplied {@code <pointcut>} and registers the resulting
	 * Pointcut with the BeanDefinitionRegistry.
	 */
	private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
		String id = pointcutElement.getAttribute(ID);
		String expression = pointcutElement.getAttribute(EXPRESSION);

		AbstractBeanDefinition pointcutDefinition = null;

		try {
			this.parseState.push(new PointcutEntry(id));
			pointcutDefinition = createPointcutDefinition(expression);
			pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));

			String pointcutBeanName = id;
			if (StringUtils.hasText(pointcutBeanName)) {
				parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
			}
			else {
				pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
			}

			parserContext.registerComponent(
					new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
		}
		finally {
			this.parseState.pop();
		}

		return pointcutDefinition;
	}

	/**
	 * Parses the {@code pointcut} or {@code pointcut-ref} attributes of the supplied
	 * {@link Element} and add a {@code pointcut} property as appropriate. Generates a
	 * {@link org.springframework.beans.factory.config.BeanDefinition} for the pointcut if  necessary
	 * and returns its bean name, otherwise returns the bean name of the referred pointcut.
	 */
	@Nullable
	private Object parsePointcutProperty(Element element, ParserContext parserContext) {
		if (element.hasAttribute(POINTCUT) && element.hasAttribute(POINTCUT_REF)) {
			parserContext.getReaderContext().error(
					"Cannot define both 'pointcut' and 'pointcut-ref' on <advisor> tag.",
					element, this.parseState.snapshot());
			return null;
		}
		else if (element.hasAttribute(POINTCUT)) {
			// Create a pointcut for the anonymous pc and register it.
			String expression = element.getAttribute(POINTCUT);
			AbstractBeanDefinition pointcutDefinition = createPointcutDefinition(expression);
			pointcutDefinition.setSource(parserContext.extractSource(element));
			return pointcutDefinition;
		}
		else if (element.hasAttribute(POINTCUT_REF)) {
			String pointcutRef = element.getAttribute(POINTCUT_REF);
			if (!StringUtils.hasText(pointcutRef)) {
				parserContext.getReaderContext().error(
						"'pointcut-ref' attribute contains empty value.", element, this.parseState.snapshot());
				return null;
			}
			return pointcutRef;
		}
		else {
			parserContext.getReaderContext().error(
					"Must define one of 'pointcut' or 'pointcut-ref' on <advisor> tag.",
					element, this.parseState.snapshot());
			return null;
		}
	}

	/**
	 * Creates a {@link BeanDefinition} for the {@link AspectJExpressionPointcut} class using
	 * the supplied pointcut expression.
	 */
	protected AbstractBeanDefinition createPointcutDefinition(String expression) {
		RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class);
		beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
		beanDefinition.setSynthetic(true);
		beanDefinition.getPropertyValues().add(EXPRESSION, expression);
		return beanDefinition;
	}

}
